import * as fs from 'fs-extra';
import * as path from 'path';
import { v4 as uuidv4 } from 'uuid';
import { Tag, TagDataFile } from '../types/tag';
import { Classify, ClassifyDataFile } from '../types/classify';

/**
 * 数据迁移脚本
 * 将public目录下的tags.json和classify.json文件迁移到server/data目录
 * 并转换数据格式以符合新的类型定义
 */
class DataMigration {
  private readonly publicDir: string;
  private readonly dataDir: string;

  constructor() {
    this.publicDir = path.join(process.cwd(), 'public');
    this.dataDir = path.join(process.cwd(), 'server', 'data');
  }

  /**
   * 执行完整的数据迁移
   */
  async migrate(): Promise<void> {
    try {
      console.log('开始数据迁移...');
      
      // 确保目标目录存在
      await this.ensureDataDirectory();
      
      // 迁移标签数据
      await this.migrateTags();
      
      // 迁移分类数据
      await this.migrateClassifies();
      
      console.log('数据迁移完成！');
    } catch (error) {
      console.error('数据迁移失败:', error);
      throw error;
    }
  }

  /**
   * 确保数据目录存在
   */
  private async ensureDataDirectory(): Promise<void> {
    await fs.ensureDir(this.dataDir);
    console.log(`数据目录已准备: ${this.dataDir}`);
  }

  /**
   * 迁移标签数据
   */
  private async migrateTags(): Promise<void> {
    const sourceFile = path.join(this.publicDir, 'tags.json');
    const targetFile = path.join(this.dataDir, 'tags.json');
    
    try {
      // 检查源文件是否存在
      if (!(await fs.pathExists(sourceFile))) {
        console.log('源标签文件不存在，跳过标签迁移');
        return;
      }
      
      // 读取源数据
      const sourceData = await fs.readJson(sourceFile);
      console.log(`读取到 ${sourceData.tags?.length || 0} 个标签`);
      
      // 转换数据格式
      const migratedTags: Tag[] = [];
      
      if (sourceData.tags && Array.isArray(sourceData.tags)) {
        for (const oldTag of sourceData.tags) {
          const newTag: Tag = {
            id: uuidv4(), // 生成新的UUID
            name: oldTag.name || '',
            description: oldTag.description || '',
            color: oldTag.color || '#666666',
            icon: oldTag.icon || 'tag',
            createdAt: oldTag.createdAt || new Date().toISOString(),
            updatedAt: oldTag.updatedAt || new Date().toISOString()
          };
          
          migratedTags.push(newTag);
        }
      }
      
      // 创建新的数据文件格式
      const newTagData: TagDataFile = {
        tags: migratedTags,
        metadata: {
          version: '1.0.0',
          lastUpdated: new Date().toISOString(),
          totalCount: migratedTags.length
        }
      };
      
      // 写入目标文件
      await fs.writeJson(targetFile, newTagData, { spaces: 2 });
      console.log(`标签数据已迁移到: ${targetFile}`);
      
      // 创建备份
      await this.createBackup(sourceFile, 'tags');
      
    } catch (error) {
      console.error('标签数据迁移失败:', error);
      throw error;
    }
  }

  /**
   * 迁移分类数据
   */
  private async migrateClassifies(): Promise<void> {
    const sourceFile = path.join(this.publicDir, 'classify.json');
    const targetFile = path.join(this.dataDir, 'classifies.json');
    
    try {
      // 检查源文件是否存在
      if (!(await fs.pathExists(sourceFile))) {
        console.log('源分类文件不存在，跳过分类迁移');
        return;
      }
      
      // 读取源数据
      const sourceData = await fs.readJson(sourceFile);
      console.log(`读取到 ${sourceData.classifies?.length || 0} 个分类`);
      
      // 转换数据格式
      const migratedClassifies: Classify[] = [];
      
      if (sourceData.classifies && Array.isArray(sourceData.classifies)) {
        for (const oldClassify of sourceData.classifies) {
          const newClassify: Classify = {
            id: uuidv4(), // 生成新的UUID
            name: oldClassify.label || oldClassify.name || '',
            value: oldClassify.label || oldClassify.name || '',
            description: oldClassify.description || '',
            color: oldClassify.color || '#666666',
            icon: oldClassify.icon || 'folder',
            parentId: null, // 旧数据没有层级结构
            isActive: true,
            sortOrder: parseInt(oldClassify.id) || 0,
            createdAt: oldClassify.createdAt || new Date().toISOString(),
            updatedAt: oldClassify.updatedAt || new Date().toISOString()
          };
          
          migratedClassifies.push(newClassify);
        }
      }
      
      // 创建新的数据文件格式
      const newClassifyData: ClassifyDataFile = {
        classifies: migratedClassifies,
        metadata: {
          version: '1.0.0',
          lastUpdated: new Date().toISOString(),
          totalCount: migratedClassifies.length
        }
      };
      
      // 写入目标文件
      await fs.writeJson(targetFile, newClassifyData, { spaces: 2 });
      console.log(`分类数据已迁移到: ${targetFile}`);
      
      // 创建备份
      await this.createBackup(sourceFile, 'classifies');
      
    } catch (error) {
      console.error('分类数据迁移失败:', error);
      throw error;
    }
  }

  /**
   * 创建源文件备份
   * @param sourceFile 源文件路径
   * @param type 数据类型
   */
  private async createBackup(sourceFile: string, type: string): Promise<void> {
    try {
      const backupDir = path.join(this.dataDir, 'backups');
      await fs.ensureDir(backupDir);
      
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      const backupFile = path.join(backupDir, `${type}-migration-backup-${timestamp}.json`);
      
      await fs.copy(sourceFile, backupFile);
      console.log(`已创建备份文件: ${backupFile}`);
    } catch (error) {
      console.warn(`创建备份失败: ${error instanceof Error ? error.message : String(error)}`);
    }
  }

  /**
   * 验证迁移结果
   */
  async validateMigration(): Promise<boolean> {
    try {
      const tagsFile = path.join(this.dataDir, 'tags.json');
      const classifiesFile = path.join(this.dataDir, 'classifies.json');
      
      let isValid = true;
      
      // 验证标签文件
      if (await fs.pathExists(tagsFile)) {
        const tagData = await fs.readJson(tagsFile);
        if (!tagData.tags || !Array.isArray(tagData.tags) || !tagData.metadata) {
          console.error('标签文件格式验证失败');
          isValid = false;
        } else {
          console.log(`标签文件验证通过，包含 ${tagData.tags.length} 个标签`);
        }
      }
      
      // 验证分类文件
      if (await fs.pathExists(classifiesFile)) {
        const classifyData = await fs.readJson(classifiesFile);
        if (!classifyData.classifies || !Array.isArray(classifyData.classifies) || !classifyData.metadata) {
          console.error('分类文件格式验证失败');
          isValid = false;
        } else {
          console.log(`分类文件验证通过，包含 ${classifyData.classifies.length} 个分类`);
        }
      }
      
      return isValid;
    } catch (error) {
      console.error('验证迁移结果失败:', error);
      return false;
    }
  }
}

// 如果直接运行此脚本
if (require.main === module) {
  const migration = new DataMigration();
  
  migration.migrate()
    .then(async () => {
      const isValid = await migration.validateMigration();
      if (isValid) {
        console.log('✅ 数据迁移成功完成并通过验证');
        process.exit(0);
      } else {
        console.error('❌ 数据迁移验证失败');
        process.exit(1);
      }
    })
    .catch((error) => {
      console.error('❌ 数据迁移失败:', error);
      process.exit(1);
    });
}

export { DataMigration };